#include "stm32f10x.h"                  // Device header

uint16_t Adc_Data[4];

void Adc_Init(void)
{
	//开启外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	
	/*开启GPIO的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	//开启ADC的RCC分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);								//开启六分频，就是12MHz，ADC最高的分频就是14MHz的，要比这个小
	
	//开启DMA的时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	//在这里配置通道，然后有四个通道都要配置
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//开启ADC的通道，选择ADC1、通道0（GPIO_A0）、1序列，采样时间选择ADC_SampleTime_55Cycles5，55的
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);
	
	//ADC初始化
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;							//ADC_ContinuousConvMode是ADC的连续模式，DISABLE或者ENABLE
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;						//ADC_DataAlign是ADC的数据是左对齐ADC_DataAlign_Left，还是右对齐ADC_DataAlign_Right
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;		//ADC_ExternalTrigConv是定义外部触发的来源，这里选择软件触发，所以用ADC_ExternalTrigConv_None不需要外部触发来源
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;							//ADC_Mode是ADC的模式，是选择双ADC模式还是单ADC模式，这里用单模式，所以用ADC_Mode_Independent
	ADC_InitStruct.ADC_NbrOfChannel = 4;									//ADC_NbrOfChannel是ADC的数据通道多少个，是从哪里来的数据
	ADC_InitStruct.ADC_ScanConvMode = ENABLE;								//ADC的扫描模式，是DISABLE或者ENABLE
	ADC_Init(ADC1,&ADC_InitStruct);		
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;							//GPIO时钟的模式需要选择AIN，也就是我们的模拟输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);									//将PA1和PA2引脚初始化为推挽输出
		
	//初始化DMA结构体
	DMA_InitTypeDef DMA_InitStruct;
	//外设的配置
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;				//外设起始地址，需要一个uint32_t类型的变量，这个是规定，所以这个地方传进来的是uint32_t
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//传递字节的大小，
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//是否自增
	//存储器的配置
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Adc_Data;					//存储器起始地址
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
	
	DMA_InitStruct.DMA_BufferSize = 4;										//DMA_BufferSize就是传输计数器的值，也是uint32_t，但是他都内部大小只有16位
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;							//DIR就是方向，看是从外设到存储器，还是从存储器到外设，SRC就是外设是来源，DST就是destination，外设是目的地
	DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;								//M2M就是 是否是 软件触发
	DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;							//Mode是自动重装的模式，需不需要自动重装，DMA_Mode_Normal就是不需要，DMA_Mode_Circular就是需要，循环
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;						//优先级，这里不一定需要那么高的优先级，随便配置的
			
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);								//因为是软件触发，所以这里是随便一个通道都可以
	
	DMA_Cmd(DMA1_Channel1,ENABLE);											//DMA1的通道1使能
	
	
	//ADC使能
	ADC_Cmd(ADC1,ENABLE);													//ADC1触发DMA1的信号使能
	ADC_DMACmd(ADC1,ENABLE);												//ADC1使能
	//ADC校准
	ADC_ResetCalibration(ADC1);										//重新设置ADC1的校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);				//当ADC重新设置ADC1的校准后，他会自动清0，所以这里用一个while判断一下，如果获取到校准的标志位还是1，就表示还没有校准完成，如果是校准完成就是0
	ADC_StartCalibration(ADC1);										//设置校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);					//当ADC完成校准后，他会自动清0，所以这里用一个while判断一下，如果获取到校准的标志位还是1，就表示还没有校准完成，如果是校准完成就是0

	ADC_SoftwareStartConvCmd(ADC1,ENABLE);	

}

//void Adc_GetData(void)
//{
//	//上面是配置DMA的配置，但是是硬件触发，所以还没有触发，调用这个是因为是单次的模式，在while里面循环，需要连续配置传输计数器
//	DMA_Cmd(DMA1_Channel1,DISABLE);											//上面是配置DMA的一次
//	DMA_SetCurrDataCounter(DMA1_Channel1,4);
//	DMA_Cmd(DMA1_Channel1,ENABLE);
//	
//	//这里ADC转化完成后，会触发DMA转运，硬件触发
//	ADC_SoftwareStartConvCmd(ADC1,ENABLE);							//因为前面没有选择外部触发，所以这个地方需要软件触发，然后软件触发之后，数据才会被转化
//	
//	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);						//获取DMA_GetFlagStatus标志位，有很多，这个DMA1_FLAG_TC1是转运完成的标志位，转运完成会置1，需要软件清零
//	DMA_ClearFlag(DMA1_FLAG_TC1);		
//}
